#!/usr/bin/php
<?php
  //
  //  Script that converts the contents of the microinstruction definitions
  //  and translates them into a verilog ROM module.
  //  Possible upgrade: Take into account the "DON'T CARE" values in the
  //  micro-instructions, so the micro instruction ROM can be smaller
  //

  // Read all the instruction definitions
  //
  $f1 = fopen("php://stdin", "r");

  if (!$f1)
    {
      echo "Error opening file\n";
      exit(1);
    }

  $str = "";
  while(!feof($f1)) $str .= fread($f1, 1024);
  fclose($f1);

  // 1. Get the array of pairs (NAME, instr)
  $arr1 = explode("######", $str);
  for($i=1, $seq=0; $i<count($arr1); $i++)
    {
      $arr2 = explode("\n", $arr1[$i]);
      for($j=1; $j<count($arr2); $j++)
        {
          $insl = trim($arr2[$j]);
          $arr3 = split("[ ]+", $insl);
          $ins  = $arr3[0];
          if (strlen($ins)<3 || strlen($ins)>6 || $ins!=strtoupper($ins) ||
              preg_match("/__/", $arr3[1])==0) break;
          $instr[$ins]['micro'][]['code'] = $arr3[1];

          if(isset($instr[$ins]['seq'])) $seq++;
          else $instr[$ins]['seq'] = $seq++;
        }
    }

  // 2. Replace x/d/m/s by zeros and remove _ from instr
  $micros = Array();

  foreach ($instr as $key => $value)
    {
      for($i=0; $i<count($value['micro']); $i++)
        {
          $microi = ereg_replace ("_", "", ereg_replace( "[xdms]", "0", 
                                  $value['micro'][$i]['code']));
          if (isset($micro_data_width)) { 
            if ($micro_data_width!=strlen($microi)) 
              die ("Instruction $key does not have the same length\n");
          } else $micro_data_width = strlen($microi);

          $instr[$key]['micro'][$i]['code'] = $microi;

          $last = intval($i == count($value['micro'])-1);
          $micros[] = $last . $microi;
        }
    }

  // 3. Export the micro rom rounded to the next power of 2
  $fm = fopen ("micro_rom.dat", "w");
  for ($i=0, $j=0; $i<count($micros); $i++)
    {
      fwrite($fm, $micros[$i] . "\n");
      if ($i == pow(2, $j)) $j++;
    }

  printf ("%d micro instructions\n", $i);

  $micro_data_width++; // we include also the last bit
  $str_zero = "";
  for ($k=0; $k<$micro_data_width; $k++) $str_zero .= "0";
  while ($i++ < pow(2, $j)) fwrite($fm, $str_zero . "\n");
  fclose($fm);

  $micro_addr_width = $j;

  // 4. Export the instruction sequencer code
  $fi = fopen ("rom_def.v", "w");
  fwrite($fi, "`define MICRO_DATA_WIDTH $micro_data_width\n");
  fwrite($fi, "`define MICRO_ADDR_WIDTH $micro_addr_width\n");
  fwrite($fi, "\n");

  foreach ($instr as $key => $value)
    fprintf ($fi, "`define $key\t$micro_addr_width'b%0${micro_addr_width}b\n",
             $value['seq']);
  fclose($fi);
?>
